package com.n9.qq.android;

import com.n9.qq.client.FromServiceMsg;
import com.n9.qq.client.ToServiceMsg;
import com.n9.qq.util.Crypter;

import java.nio.ByteBuffer;
import java.util.Objects;

/**
 * @author ice
 * @since 2019/2/15 16:22
 */
public class AqToServiceMsg implements ToServiceMsg {
    public static final int CMD_0801 = 0x0801;
    public static final int CMD_0802 = 0x0802;
    public static final int CMD_0901 = 0x0901;
    public static final int CMD_0902 = 0X0902;

    private long qqUin;
    private ReqHead reqHead;
    private byte[] body;
    private byte[] token;
    private byte[] key;
    private int requestId;
    private int cmd;
    private FromServiceMsg fromServiceMsg;

    private AqToServiceMsg() {
    }

    /**
     * 创建0802的发送数据包
     * @param reqHead
     * @param body
     * @param context
     * @return
     */
    public static AqToServiceMsg create0802(ReqHead reqHead, byte[] body, AqContext context) {
        AqToServiceMsg toServiceMsg = new AqToServiceMsg();
        toServiceMsg.qqUin = context.getQqUin();
        toServiceMsg.body = body;
        toServiceMsg.reqHead = reqHead;
        toServiceMsg.requestId = reqHead.getRequestId();
        toServiceMsg.key = context.getDefaultKey();
        toServiceMsg.token = context.getToken0143();
        toServiceMsg.cmd = CMD_0802;
        return toServiceMsg;
    }

    /**
     * 创建0201的发送数据包
     * @param reqHead
     * @param body
     * @param context
     * @return
     */
    public static AqToServiceMsg create0801(ReqHead reqHead, byte[] body, AqContext context) {
        AqToServiceMsg toServiceMsg = new AqToServiceMsg();
        toServiceMsg.qqUin = context.getQqUin();
        toServiceMsg.body = body;
        toServiceMsg.reqHead = reqHead;
        toServiceMsg.requestId = reqHead.getRequestId();
        toServiceMsg.key = context.getSessionKey();
        toServiceMsg.token = context.getToken0143();
        toServiceMsg.cmd = CMD_0801;
        return toServiceMsg;
    }

    /**
     * 创建0901的发送数据包
     * @param reqHead
     * @param body
     * @param context
     * @return
     */
    public static AqToServiceMsg create0901(ReqHead reqHead, byte[] body, AqContext context) {
        return create0901(reqHead, body, context, context.getRequestId());
    }

    /**
     * 创建0901的发送数据包
     * @param reqHead
     * @param body
     * @param context
     * @param requestId
     * @return
     */
    public static AqToServiceMsg create0901(ReqHead reqHead, byte[] body, AqContext context, int requestId) {
        AqToServiceMsg toServiceMsg = new AqToServiceMsg();
        toServiceMsg.qqUin = context.getQqUin();
        toServiceMsg.body = body;
        toServiceMsg.reqHead = reqHead;
        toServiceMsg.key = context.getSessionKey();
        toServiceMsg.requestId = requestId;
        toServiceMsg.cmd = CMD_0901;
        return toServiceMsg;
    }

    /**
     * @param qqUin
     * @param reqHead
     * @param body
     * @param token         token0143
     * @param key
     * @param requestId
     * @param cmd
     */
    public AqToServiceMsg(long qqUin, ReqHead reqHead, byte[] body, byte[] token, byte[] key, int requestId, int cmd) {
        this.qqUin = qqUin;
        this.reqHead = reqHead;
        this.body = body;
        this.token = Objects.isNull(token) ? new byte[0] : token;
        this.key = key;
        this.requestId = requestId;
        this.cmd = cmd;
    }

    @Override
    public Integer getId() {
        return requestId;
    }

    @Override
    public byte[] getBytes() {
        byte[] encryptData = getEncryptData();
        if (cmd == CMD_0801 || cmd == CMD_0802) {
            return get08PackageData(encryptData);
        } else if (cmd == CMD_0901) {
            return get09PackageData(encryptData);
        } else {
            return encryptData;
        }
    }

    private byte[] get09PackageData(byte[] encryptData) {
        byte[] qqUinBytes = Long.toString(qqUin).getBytes();
        final int packetLen = 4 + 1 + 4 + 4 + 1 + 4 +  qqUinBytes.length + encryptData.length;
        ByteBuffer buf = ByteBuffer.allocate(packetLen);

        buf.putInt(packetLen);
        buf.put((byte)0);
        buf.putInt(cmd);
        buf.putInt(requestId);
        buf.put((byte)0);
        buf.putInt(qqUinBytes.length + 4);
        buf.put(qqUinBytes);
        buf.put(encryptData);
        buf.flip();
        return buf.array();
    }

    private byte[] get08PackageData(byte[] encryptData) {
        if (Objects.isNull(token)) {
            token = new byte[0];
        }
        final int tokenFullLen = 4 + token.length;
        byte[] qqUinBytes = Long.toString(qqUin).getBytes();
        final int packetLen = 4 + 1 + 4 +  tokenFullLen + 4 + 1 + qqUinBytes.length + encryptData.length;

        ByteBuffer buf = ByteBuffer.allocate(packetLen);
        buf.putInt(packetLen);
        buf.put((byte)0);
        buf.putInt(cmd);
        buf.putInt(tokenFullLen);
        buf.put(token);
        buf.put((byte)0);
        buf.putInt(qqUinBytes.length + 4);
        buf.put(qqUinBytes);
        buf.put(encryptData);

        return buf.array();
    }

    private byte[] getEncryptData() {
        byte[] reqHeadData = reqHead.getData();
        byte[] data = new byte[reqHeadData.length + body.length];

        final int headLen = reqHeadData.length;
        System.arraycopy(reqHeadData, 0 , data, 0, headLen);
        System.arraycopy(body, 0, data, headLen, body.length);
        if (Objects.nonNull(key)) {
            data = new Crypter().encrypt(data, key);
        }
        return data;
    }

    @Override
    public FromServiceMsg getFromServiceMsg() {
        return fromServiceMsg;
    }
    @Override
    public void setFromServiceMsg(FromServiceMsg fromServiceMsg) {
        this.fromServiceMsg = fromServiceMsg;
    }
}
